package com.ld.shieldsb.dao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

import com.ld.shieldsb.annotation.dao.EscapeHtml;
import com.ld.shieldsb.annotation.field.ModelBasicField.createBy;
import com.ld.shieldsb.annotation.field.ModelBasicField.createName;
import com.ld.shieldsb.annotation.field.ModelBasicField.createTime;
import com.ld.shieldsb.annotation.field.ModelBasicField.modifyBy;
import com.ld.shieldsb.annotation.field.ModelBasicField.updateBy;
import com.ld.shieldsb.annotation.field.ModelBasicField.updateName;
import com.ld.shieldsb.annotation.field.ModelBasicField.updateTime;
import com.ld.shieldsb.annotation.field.SensitiveWords;
import com.ld.shieldsb.annotation.field.db.IdType;
import com.ld.shieldsb.annotation.field.db.OnlyShow;
import com.ld.shieldsb.annotation.field.db.TableId;
import com.ld.shieldsb.annotation.util.AnnotationUtil;
import com.ld.shieldsb.annotation.util.TableNameUtil;
import com.ld.shieldsb.common.composition.util.PKUtil;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.core.util.date.DateUtil;
import com.ld.shieldsb.common.core.util.sensitiveWord.ISensitiveWordAfterHandler;
import com.ld.shieldsb.common.core.util.sensitiveWord.SensitiveWordFactory;
import com.ld.shieldsb.common.core.util.sensitiveWord.SensitiveWordResult;
import com.ld.shieldsb.dao.exception.SensitiveWordContainsException;
import com.ld.shieldsb.dao.model.QueryModel;
import com.ld.shieldsb.dao.model.SqlModel;
import com.ld.shieldsb.dao.util.LogUtil;
import com.ld.shieldsb.dao.util.SystemSessionInfo;
import com.ld.shieldsb.dao.util.UUIDUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * BasicDao整合tablename类型
 * 
 * @ClassName BasicDao
 * @author <a href="mailto:donggongai@126.com" target="_blank">kevin</a>
 * @date 2016年8月26日 上午10:27:17
 *
 */
@Slf4j
public abstract class BasicDao {
    protected ThreadLocal<Exception> exceptionThreadLocal;

    protected Boolean canSave = true; // 是否可保存，用于控制保存到数据库
    protected Boolean canRead = false; // 是否可读取，用于控制从数据库中读取
    protected String tableNameAlias = "tb"; // 表的别名

    protected static final QueryRunner QRY_RUN = new QueryRunner();

    @SuppressWarnings("unchecked")
    protected Class<Object> getModelClass() {
        return (Class<Object>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    // Integer结果集的处理器
    private ResultSetHandler<Integer> countRsHandler = new ResultSetHandler<Integer>() {
        public Integer handle(ResultSet rs) throws SQLException {
            if (rs.next()) {
                return rs.getInt(1);
            }
            return 0;
        }
    };
    // long结果集的处理器
    private ResultSetHandler<Long> longRsHandler = new ResultSetHandler<Long>() {
        public Long handle(ResultSet rs) throws SQLException {
            if (rs.next()) {
                return rs.getLong(1);
            }
            return 0L;
        }
    };
    // 单对象结果集的处理器，不转成对应的对象，直接返回结果集中的对象
    private ResultSetHandler<Object> objectRsHandler = new ResultSetHandler<Object>() {
        public Object handle(ResultSet rs) throws SQLException {
            if (rs.next()) {
                return rs.getObject(1);
            }
            return null;
        }
    };
    // list（Object）结果集的处理器，不转成对应的对象，直接返回结果集中的对象
    private ResultSetHandler<List<Object>> objRsListHandler = new ResultSetHandler<List<Object>>() {

        @Override
        public List<Object> handle(ResultSet rs) throws SQLException {
            List<Object> longList = new ArrayList<>();
            while (rs.next()) {
                longList.add(rs.getObject(1));
            }
            return longList;
        }
    };
    // list（Long）结果集的处理器，不转成对应的对象，直接返回结果集中的对象
    private ResultSetHandler<List<Long>> longRsListHandler = new ResultSetHandler<List<Long>>() {

        @Override
        public List<Long> handle(ResultSet rs) throws SQLException {
            List<Long> longList = new ArrayList<>();
            while (rs.next()) {
                longList.add(rs.getLong(1));
            }
            return longList;
        }
    };

    public BasicDao() {
    }

    // 抽象方法
    protected abstract Connection getCon() throws Exception;

    protected abstract void closeCon(Connection connection) throws Exception;

    public abstract int update(String sql, Object... params);

    public abstract int batchUpdate(String sql, Object[][] params);

    public final int getCount(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return -1;
            }
            try {
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, countRsHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return -1;
        }
    }

    /**
     * dao调试日志
     * 
     * @Title daoDebug
     * @author 吕凯
     * @date 2021年1月15日 下午5:28:20
     * @param sql
     * @param params
     *            void
     */
    protected void outDebugLog(String sql, Object... params) {
        LogUtil.daoDebug("sql: " + sql + " params: " + Arrays.asList(params), 2); // 调用下标为2的traceEle元素，因为前面2层为工具类
    }

    /**
     * 事务的异常处理
     * 
     * @Title transactionExcetionDeal
     * @author 吕凯
     * @date 2021年1月15日 下午5:26:38
     * @param sql
     *            void
     */
    protected void transactionExcetionDeal(String sql) {
        log.warn("检测到事务中存在异常(当前sql：" + sql + ")查询操作将不执行", getException());
    }

    public final long getLongThrowException(String sql, Object... params) throws Exception {
        Connection connection = getCon();
        if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
            transactionExcetionDeal(sql);
            return -1;
        }
        try {
            outDebugLog(sql, params);
            return QRY_RUN.query(connection, sql, longRsHandler, params);
        } finally {
            if (connection.getAutoCommit()) {
                closeCon(connection);
            }
        }
    }

    public final long getLong(String sql, Object... params) {
        try {
            return getLongThrowException(sql, params);
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return 0;
        }
    }

    /**
     * dao错误日志
     * 
     * @Title outErrorLog
     * @author 吕凯
     * @date 2021年1月15日 下午5:30:09
     * @param sql
     * @param e
     *            void
     */
    private void outErrorLog(String sql, Exception e) {
        log.error("查询出错,sql:" + sql, e);
    }

    public final Object getObject(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return -1;
            }
            try {
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, objectRsHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return null;
        }
    }

    public final List<Object> getObjectList(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return Collections.emptyList();
            }
            try {
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, objRsListHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return Collections.emptyList();
        }
    }

    public final List<Long> getLongList(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return null;
            }
            try {
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, longRsListHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return null;
        }
    }

    public final Map<String, Object> getMap(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return new HashMap<>();
            }
            try {
                outDebugLog(sql, params);
                Map<String, Object> map = QRY_RUN.query(connection, sql, new MapHandler(), params);
                if (map == null) {
                    map = new HashMap<>();
                }
                return map;
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return new HashMap<>();
        }
    }

    public final List<Map<String, Object>> getMapList(String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return null;
            }
            try {
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, new MapListHandler(new MapRowProcessor()), params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return null;
        }
    }

    public final <T> T getOne(Class<T> classOfT, String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return null;
            }
            try {
                ResultSetHandler<T> resultSetHandler = new BeanHandler<>(classOfT, new BasicRowProcessor(new MyBeanProcessor()));
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, resultSetHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return null;
        }
    }

    public final <T> List<T> getList(Class<T> classOfT, String sql, Object... params) {
        try {
            Connection connection = getCon();
            if (!connection.getAutoCommit() && getException() != null) { // 非自动提交（即在事务中）存在异常则中止执行
                transactionExcetionDeal(sql);
                return new ArrayList<>();
            }
            try {
                ResultSetHandler<List<T>> resultListSetHandler = new BeanListHandler<>(classOfT,
                        new BasicRowProcessor(new MyBeanProcessor()));
                outDebugLog(sql, params);
                return QRY_RUN.query(connection, sql, resultListSetHandler, params);
            } finally {
                if (connection.getAutoCommit()) {
                    closeCon(connection);
                }
            }
        } catch (Exception e) {
            setException(e);
            outErrorLog(sql, e);
            return new ArrayList<>();
        }
    }

    /* 公共方法 */

    /**
     * 
     * 根据条件判断某个bean是否存在
     * 
     * @Title exists
     * @param classOfT
     *            bean
     * @param queryModel
     *            查询条件
     * @return boolean
     */
    public <T> boolean exists(Class<T> classOfT, QueryModel queryModel) {
        String tableName = getTableName(classOfT);
        String sql = "select 1 from " + tableName + " " + queryModel.getNoOrderQueryStr();
        return getLong(sql, queryModel.getParams()) > 0;
    }

    public <T> String getTableName(Class<T> classOfT) {
        return TableNameUtil.getTableName(classOfT);
    }

    public <T> String getTableName(T obj) {
        return TableNameUtil.getTableName(obj);
    }

    public <T> List<T> findList(Class<T> classOfT, String key, Object value) {
        String tableName = getTableName(classOfT);
        String sql = "select * from " + tableName + " where " + key + "=?";
        LogUtil.daoDebug("sql: " + sql + " params: " + value);
        return getList(classOfT, sql, value);
    }

    public <T> List<T> findAllList(Class<T> classOfT) {
        String tableName = getTableName(classOfT);
        String sql = "select * from " + tableName;
        LogUtil.daoDebug("sql: " + sql + " params: ");
        return getList(classOfT, "select * from " + tableName);
    }

    public <T> List<T> findListBySql(Class<T> classOfT, String queryStr) {
        String tableName = getTableName(classOfT);
        String sql = "select * from " + tableName + " where " + queryStr;
        LogUtil.daoDebug("sql: " + sql + " params: ");
        return getList(classOfT, sql);
    }

    /**
     * 
     * 根据主键id删除某条数据
     * 
     * @Title delete
     * @param classOfT
     *            bean
     * @param id
     *            主键id
     * @return boolean
     */
    public <T> boolean delete(Class<T> classOfT, Object id) {
        return delete(classOfT, "id", id);
    }

    /**
     * 
     * 根据条件字段值删除数据
     * 
     * @Title delete
     * @param classOfT
     *            bean
     * @param key
     *            字段
     * @param value
     *            字段值
     * @return boolean
     */
    public <T> boolean delete(Class<T> classOfT, String key, Object value) {
        String tableName = getTableName(classOfT);
        String sql = "delete from " + tableName + " where " + key + "=?";
        LogUtil.daoDebug("sql: " + sql + " params: " + value);
        return update(sql, value) > 0;
    }

    /**
     * 
     * 根据id批量删除数据
     * 
     * @Title batchDelete
     * @param classOfT
     * @param ids
     *            id
     * @return boolean
     */
    public <T> boolean batchDelete(Class<T> classOfT, Object... ids) {
        return batchDelete(classOfT, "id", ids);
    }

    /**
     * 
     * 根据id批量删除数据
     * 
     * @Title batchDelete
     * @param classOfT
     * @param ids
     *            id
     * @return boolean
     */
    public <T> boolean delete(Class<T> classOfT, List<Object> ids) {
        return batchDelete(classOfT, "id", ids.toArray());
    }

    /**
     * 
     * 根据具体字段批量删除数据
     * 
     * @Title batchDelete
     * @param classOfT
     * @param key
     *            字段
     * @param ids
     *            字段值
     * @return boolean
     */
    public <T> boolean batchDelete(Class<T> classOfT, String key, Object... ids) {
        String tableName = getTableName(classOfT);
        String sql = "delete from " + tableName + " where " + key + "=?";
        final int arrNum = 1;
        Object[][] params = new Object[ids.length][arrNum];
        for (int i = 0; i < ids.length; i++) {
            params[i][0] = ids[i];
        }
        return batchUpdate(sql, params) > 0;
    }

    /**
     * 
     * 通过id进行保存或更新
     * 
     * @Title update
     * @param modelBean
     *            实体bean
     * @param ids
     *            主键id
     * @return boolean
     */
    @EscapeHtml
    public <T> boolean update(T modelBean, String... ids) {
        return update(modelBean, false, ids);
    }

    @SuppressWarnings("unchecked")
    @EscapeHtml
    public <T> boolean update(T modelBean, boolean updateAllField, String... ids) {
        if (modelBean != null) {
            if (ids.length == 0) {
                Object id = AnnotationUtil.getModelId(modelBean);
                if (id == null) {
                    log.warn("更新失败，模型id为空!", new Exception());
                    return false;
                }
            }
            ids = toLowerCaseIds(ids);
            Map<String, Field> fieldMap = new HashMap<String, Field>();
            Map<String, Object> objMap = getSqlObjMap(modelBean, updateAllField, fieldMap, false);
            Class<T> classOfT = (Class<T>) modelBean.getClass();
            SqlModel sqlModel = getUpdateSqlModel(classOfT, objMap, ids);
            if (fieldMap != null && !fieldMap.isEmpty() && canSave) {
                SqlModel sqlQueryModel = getPkSqlModel(classOfT, objMap, fieldMap, ids);// 原来的值
                T oldModelBean = getOne(classOfT, sqlQueryModel.getSql(), sqlQueryModel.getParams());
                updateIndexFieldContrast(modelBean, oldModelBean, fieldMap);// 修改原来的值
            }
            return update(sqlModel.getSql(), sqlModel.getParams()) > 0;
        }
        return false;
    }

    /**
     * 根据id更新指点字段
     * 
     * @Title updateById
     * @author 吕凯
     * @date 2016年8月16日 上午8:17:46
     * @param fieldName
     *            字段
     * @param fieldValue
     *            字段值
     * @return boolean
     */
    public <T> boolean updateById(Class<T> classOfT, Object id, String fieldName, Object fieldValue) {
        if (!StringUtils.isBlank(fieldName)) {
            String tableName = getTableName(classOfT);
            String sql = "UPDATE " + tableName + " SET " + fieldName + "=? WHERE id=? ";
            return update(sql, fieldValue, id) > 0;
        }
        return false;
    }

    /**
     * 转换为小写
     * 
     * @param ids
     * @return
     */
    private String[] toLowerCaseIds(String... ids) {
        String[] newIds = new String[ids.length];
        for (int i = 0; i < ids.length; i++) {
            newIds[i] = ids[i].toLowerCase();
        }
        return newIds;
    }

    /**
     * 
     * 通过id进行保存或更新 允许设为null
     * 
     * @Title updateEvenNull
     * @param modelBean
     * @param fields
     *            字段
     * @param ids
     *            字段值
     * @return boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean updateEvenNull(T modelBean, String fields, String... ids) {
        if (modelBean != null) {
            if (ids.length == 0) {
                Object id = AnnotationUtil.getModelId(modelBean);
                if (id == null) {
                    log.warn("更新失败，模型id为空!", new Exception());
                    return false;
                }
            }
            ids = toLowerCaseIds(ids);
            Map<String, Field> fieldMap = new HashMap<String, Field>();
            Map<String, Object> objMap = getFieldsSqlObjMap(modelBean, fields, fieldMap, false);
            Class<T> classOfT = (Class<T>) modelBean.getClass();
            SqlModel sqlModel = getUpdateSqlModel(classOfT, objMap, ids);
            if (fieldMap != null && !fieldMap.isEmpty() && canSave) {
                SqlModel sqlQueryModel = getPkSqlModel(classOfT, objMap, fieldMap, ids);// 原来的值
                T oldModelBean = getOne(classOfT, sqlQueryModel.getSql(), sqlQueryModel.getParams());
                updateIndexFieldContrast(modelBean, oldModelBean, fieldMap);// 修改原来的值
            }
            return update(sqlModel.getSql(), sqlModel.getParams()) > 0;
        }
        return false;
    }

    /**
     * 
     * 更新全部字段
     * 
     * @Title updateAllField
     * @param modelBean
     *            实体bean
     * @param ids
     *            条件
     * @return boolean
     */
    @SuppressWarnings("unchecked")
    public <T> boolean updateAllField(T modelBean, String... ids) {
        if (modelBean != null) {
            if (ids.length == 0) {
                Object id = AnnotationUtil.getModelId(modelBean);
                if (id == null) {
                    log.warn("更新失败，模型id为空!", new Exception());
                    return false;
                }
            }
            ids = toLowerCaseIds(ids);
            Class<T> classOfT = (Class<T>) modelBean.getClass();
            Map<String, Field> fieldMap = new HashMap<String, Field>();
            Map<String, Object> objMap = getSqlObjMap(modelBean, true, fieldMap, false);
            SqlModel sqlModel = getUpdateSqlModel(classOfT, objMap, ids);
            if (fieldMap != null && !fieldMap.isEmpty() && canSave) {
                SqlModel sqlQueryModel = getPkSqlModel(classOfT, objMap, fieldMap, ids);// 原来的值
                T oldModelBean = getOne(classOfT, sqlQueryModel.getSql(), sqlQueryModel.getParams());
                updateIndexFieldContrast(modelBean, oldModelBean, fieldMap);// 修改原来的值
            }
            return update(sqlModel.getSql(), sqlModel.getParams()) > 0;
        }
        return false;
    }

    /**
     * 批量更新modelBean
     * 
     * @Title update
     * @param modelBeans
     *            list bean
     * @param ids
     *            条件
     * @return int
     */
    @SuppressWarnings("unchecked")
    @EscapeHtml
    public <T> int update(List<T> modelBeans, String... ids) {
        if (modelBeans != null && !modelBeans.isEmpty()) {
            Class<T> classOfT = (Class<T>) modelBeans.get(0).getClass();
            Object[][] params = new Object[modelBeans.size()][];
            String sql = null;
            int i = 0;
            ids = toLowerCaseIds(ids);
            for (T modelBean : modelBeans) {
                Map<String, Field> fieldMap = new HashMap<String, Field>();
                Map<String, Object> objMap = getSqlObjMap(modelBean, false, fieldMap, false);
                SqlModel sqlModel = getUpdateSqlModel(classOfT, objMap, ids);
                params[i++] = sqlModel.getParams();
                if (sql == null) {
                    sql = sqlModel.getSql();
                }
                if (fieldMap != null && !fieldMap.isEmpty() && canSave) {
                    SqlModel sqlQueryModel = getPkSqlModel(classOfT, objMap, fieldMap, ids);// 原来的值
                    T oldModelBean = getOne(classOfT, sqlQueryModel.getSql(), sqlQueryModel.getParams());
                    updateIndexFieldContrast(modelBean, oldModelBean, fieldMap);// 修改原来的值
                }
            }
            return batchUpdate(sql, params);
        }
        return 0;
    }

    /**
     * 
     * 根据条件更新model里面的字段，字段在map
     * 
     * @Title updateByMap
     * @param classOfT
     * @param modelMap
     *            存放更新的字段map
     * @param ids
     *            条件
     * @return boolean
     */
    public <T> boolean updateByMap(Class<T> classOfT, Map<String, Object> modelMap, String... ids) {
        if (modelMap == null) {
            log.warn("更新失败，模型为空!", new Exception());
            return false;
        }
        if (ids.length == 0) {
            Object id = modelMap.get("id");
            if (id == null) {
                log.warn("更新失败，模型id为空!", new Exception());
                return false;
            }
        }
        ids = toLowerCaseIds(ids);
        SqlModel sqlModel = getUpdateSqlModel(classOfT, modelMap, ids);
        return update(sqlModel.getSql(), sqlModel.getParams()) > 0;
    }

    /**
     * 
     * 保存单个实体bean
     * 
     * @Title save
     * @param modelBean
     * @return boolean
     */
    @EscapeHtml
    public <T> boolean save(T modelBean) {
        if (modelBean != null) {
            SqlModel sqlModel = getInsertSqlModel(modelBean, false);
            return update(sqlModel.getSql(), sqlModel.getParams()) > 0;
        }
        return false;
    }

    /**
     * 
     * 保存list实体bean
     * 
     * @Title save
     * @param modelBeans
     * @return int
     */
    @EscapeHtml
    public <T> int save(List<T> modelBeans) {
        if (modelBeans != null && !modelBeans.isEmpty()) {
            Object[][] params = new Object[modelBeans.size()][];
            String sql = null;
            int i = 0;
            for (T modelBean : modelBeans) {
                SqlModel sqlModel = getInsertSqlModel(modelBean, true);
                params[i++] = sqlModel.getParams();
                if (sql == null) {
                    sql = sqlModel.getSql();
                }
            }
            return batchUpdate(sql, params);
        }
        return 0;
    }

    private boolean isSupportedType(Class<?> fieldType) {
        // 8种基本类型，Number的子类，String、java.util.Date、java.sql.Timestamp，byte数组
        return fieldType.isPrimitive() || Number.class.isAssignableFrom(fieldType) || fieldType.equals(String.class)
                || fieldType.equals(Date.class) || fieldType.equals(Timestamp.class) || fieldType.equals(byte[].class);
    }

    protected <T> SqlModel getInsertSqlModel(T modelBean, boolean isAll) {
        String tableName = getTableName(modelBean);
        Map<String, Object> objMap = getSqlObjMap(modelBean, isAll, null, true);
        SqlModel sqlModel = new SqlModel();
//        String keySql = "";
        StringBuilder keySqlSb = new StringBuilder("");
//        String insertValueSql = "";
        StringBuilder insertValueSqlSb = new StringBuilder("");
        for (Entry<String, Object> e : objMap.entrySet()) {
            Object value = e.getValue();
//            keySql += "," + e.getKey();
            keySqlSb.append(",").append(e.getKey());
//            insertValueSql += ",?";
            insertValueSqlSb.append(",?");
            sqlModel.addParam(value);

        }
        sqlModel.setSql("insert into " + tableName + "(" + keySqlSb.toString().substring(1) + ") values("
                + insertValueSqlSb.toString().substring(1) + ")");
        return sqlModel;
    }

    // fileMap 用于存放需要记录图片、附件索引的字段
    private <T> Map<String, Object> getSqlObjMap(T modelBean, boolean isAll, Map<String, Field> fileMap, boolean insert) {

        if (insert) {
            initCreate(modelBean);
        }
        initUpdate(modelBean);
        Map<String, Object> objMap = new HashMap<String, Object>();
        Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(modelBean.getClass());
        for (Entry<String, Field> e : fieldMap.entrySet()) {
            Field field = e.getValue();
            // 判断是否为private属性
            if (field.getModifiers() == 2) {
                field.setAccessible(true);
                try {
                    updateIndexField(modelBean, field, fileMap);
                    Object value = field.get(modelBean);
                    OnlyShow OnlyShowTag = field.getAnnotation(OnlyShow.class);
                    boolean onlyShow = false;
                    if (OnlyShowTag != null && OnlyShowTag.value()) {
                        onlyShow = true;
                    }
                    if (!onlyShow && (isAll || value != null)) {
                        Class<?> type = field.getType();
                        // 只添加支持的类型
                        if (isSupportedType(type)) {
                            objMap.put(e.getKey(), value);
                        } else {
                            log.debug("sql类型过滤，对象类型:" + modelBean.getClass() + ",属性名称:" + e.getKey() + ",属性类型:" + type);
                        }
                    }
                } catch (Exception e1) {
                    exceptionThreadLocal.set(e1);
                    log.error("", e1);
                }
            }
        }
        return objMap;
    }

    private <T> void initCreate(T modelBean) {
        Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(modelBean.getClass());

        fieldMap.forEach((key, field) -> {
            if (field.getModifiers() == 2) {
                field.setAccessible(true);
                try {
                    Object value = field.get(modelBean);
                    OnlyShow OnlyShowTag = field.getAnnotation(OnlyShow.class);
                    boolean onlyShow = false;
                    if (OnlyShowTag != null && OnlyShowTag.value()) {
                        onlyShow = true;
                    }
                    if (!onlyShow && value == null) {
                        Class<?> type = field.getType();
                        // 只添加支持的类型
                        if (isSupportedType(type)) {
                            // UUIDUtils
                            TableId tableId = field.getAnnotation(TableId.class);
                            if (tableId != null) {
                                if (tableId.type() == IdType.ID) {
                                    field.set(modelBean, PKUtil.nextId());
                                } else if (tableId.type() == IdType.UUID) {
                                    if (type.equals(String.class)) {
                                        field.set(modelBean, UUIDUtils.getUUID());
                                    } else {
                                        log.error("uuid主键类型不匹配，uuid字段类型必须是string");
                                    }
                                } else if (tableId.type() == IdType.AUTO) {
                                    field.set(modelBean, null);
                                } else {
                                    field.set(modelBean, PKUtil.nextId());
                                }
                            } else if (key.toLowerCase().equals("id")) {
                                field.set(modelBean, PKUtil.nextId());
                            }

                            createBy createBy = field.getAnnotation(createBy.class);
                            createTime createTime = field.getAnnotation(createTime.class);
                            createName createName = field.getAnnotation(createName.class);
                            if ((createBy != null || key.toLowerCase().equals("createby")) && value == null) {
                                field.set(modelBean, SystemSessionInfo.getUserId());
                            } else if ((createName != null || key.toLowerCase().equals("createname")) && value == null) {
                                field.set(modelBean, SystemSessionInfo.getUserName());
                            } else if ((createTime != null || key.toLowerCase().equals("createtime")) && value == null) {
                                if (type.equals(Date.class)) {
                                    field.set(modelBean, new Date());
                                } else {
                                    field.set(modelBean, DateUtil.getDateStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                                }
                            }

                        } else {
                        }
                    }
                    SensitiveWords sensitiveWords = field.getAnnotation(SensitiveWords.class);
                    if (sensitiveWords != null && field.getType().equals(String.class)) {
                        String filtertype = "simple";
                        if (StringUtils.isNotEmpty(sensitiveWords.type())) {
                            filtertype = sensitiveWords.type();
                        }
                        SensitiveWordResult result = SensitiveWordFactory.dealSensitiveWord(value.toString(), filtertype,
                                sensitiveWords.replaceStr());
                        SensitiveWords classSensitiveWord = modelBean.getClass().getAnnotation(SensitiveWords.class);
                        ISensitiveWordAfterHandler afterHandler = (ISensitiveWordAfterHandler) classSensitiveWord.classes().newInstance();
                        if (afterHandler instanceof ISensitiveWordAfterHandler) {
                            result = afterHandler.handler(result, modelBean);
                        }
                        if (result.contains) {
                            throw new SensitiveWordContainsException("数据存在敏感词:" + result.getSensitiveWordStr() + ",请修改后再提交！");
                        }
                        if (result.contains) {
                            field.set(modelBean, result.getFilteredContent());
                        }
                    }

                } catch (Exception e1) {
                    if (e1 instanceof SensitiveWordContainsException) {
                        throw new SensitiveWordContainsException(e1.getMessage());
                    }
                }
            }
        });

    }

    private <T> void initUpdate(T modelBean) {
        Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(modelBean.getClass());
        fieldMap.forEach((key, field) -> {
            if (field.getModifiers() == 2) {
                field.setAccessible(true);
                try {
                    Object value = field.get(modelBean);
                    OnlyShow OnlyShowTag = field.getAnnotation(OnlyShow.class);
                    boolean onlyShow = false;
                    if (OnlyShowTag != null && OnlyShowTag.value()) {
                        onlyShow = true;
                    }
                    if (!onlyShow && value == null) {
                        Class<?> type = field.getType();
                        // 只添加支持的类型
                        if (isSupportedType(type)) {
                            modifyBy modifyBy = field.getAnnotation(modifyBy.class);
                            updateBy updateBy = field.getAnnotation(updateBy.class);
                            updateTime updateTime = field.getAnnotation(updateTime.class);
                            updateName updateName = field.getAnnotation(updateName.class);
                            if ((updateBy != null || modifyBy != null || key.toLowerCase().equals("modifyby")
                                    || key.toLowerCase().equals("updateby")) && value == null) {
                                field.set(modelBean, SystemSessionInfo.getUserId());
                            } else if ((updateName != null || key.toLowerCase().equals("updatename")) && value == null) {
                                field.set(modelBean, SystemSessionInfo.getUserName());
                            } else if ((updateTime != null || key.toLowerCase().equals("updatetime")) && value == null) {
                                if (type.equals(Date.class)) {
                                    field.set(modelBean, new Date());
                                } else {
                                    field.set(modelBean, DateUtil.getDateStr(new Date(), "yyyy-MM-dd HH:mm:ss"));
                                }
                            }

                        } else {
                        }
                    }

                    SensitiveWords sensitiveWords = field.getAnnotation(SensitiveWords.class);
                    if (sensitiveWords != null && field.getType().equals(String.class)) {
                        String filtertype = "simple";
                        if (StringUtils.isNotEmpty(sensitiveWords.type())) {
                            filtertype = sensitiveWords.type();
                        }
                        SensitiveWordResult result = SensitiveWordFactory.dealSensitiveWord(value.toString(), filtertype,
                                sensitiveWords.replaceStr());
                        SensitiveWords classSensitiveWord = modelBean.getClass().getAnnotation(SensitiveWords.class);
                        ISensitiveWordAfterHandler afterHandler = (ISensitiveWordAfterHandler) classSensitiveWord.classes().newInstance();
                        if (afterHandler instanceof ISensitiveWordAfterHandler) {
                            result = afterHandler.handler(result, modelBean);
                        }
                        if (result.contains) {
                            throw new SensitiveWordContainsException("数据存在敏感词:" + result.getSensitiveWordStr() + ",请修改后再提交！");
                        }
                        if (result.contains) {
                            field.set(modelBean, result.getFilteredContent());
                        }
                    }
                } catch (Exception e1) {
                    e1.printStackTrace();
                    if (e1 instanceof SensitiveWordContainsException) {
                        throw new SensitiveWordContainsException(e1.getMessage());
                    }
                }
            }
        });

    }

    // 获取sql对象的map，用于数值型更新
    private <T> Map<String, Object> getFieldsSqlObjMap(T modelBean, String fields, Map<String, Field> fileMap, boolean insert) {
        if (insert) {
            initCreate(modelBean);
        }
        initUpdate(modelBean);
        Map<String, Object> objMap = new HashMap<String, Object>();
        if (fields != null) {
            List<String> fieldList = Arrays.asList(fields.toLowerCase().split(","));
            if (fieldList != null && !fieldList.isEmpty()) {
                Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(modelBean.getClass());
                for (Entry<String, Field> e : fieldMap.entrySet()) {
                    Field field = e.getValue();
                    // 判断是否为private属性
                    OnlyShow onlyShowTag = field.getAnnotation(OnlyShow.class);
                    boolean onlyShow = false;
                    if (onlyShowTag != null && onlyShowTag.value()) {
                        onlyShow = true;
                    }
                    if (field.getModifiers() == 2 && !onlyShow) {
                        field.setAccessible(true);
                        try {
                            updateIndexField(modelBean, field, fileMap);
                            Object value = field.get(modelBean);
                            // 包含指定字段，或者，字段值不为空
                            if (fieldList.contains(field.getName().toLowerCase()) || value != null) {
                                Class<?> type = field.getType();
                                // 只添加支持的类型
                                if (isSupportedType(type)) {
                                    objMap.put(e.getKey(), value);
                                } else {
                                    log.debug("sql类型过滤，对象类型:" + modelBean.getClass() + ",属性名称:" + e.getKey() + ",属性类型:" + type);
                                }
                            }
                        } catch (Exception e1) {
                            log.error("", e1);
                        }
                    }

                }

            }
        }
        return objMap;
    }

    // 更新图片、附件索引
    protected abstract <T> void updateIndexField(T modelBean, Field field, Map<String, Field> fileMap)
            throws IllegalArgumentException, IllegalAccessException;

    // 与原来数据对比更新图片、附件索引
    protected abstract <T> void updateIndexFieldContrast(T modelBean, T OldmodelBean, Map<String, Field> fieldMap);

    private <T> SqlModel getUpdateSqlModel(Class<T> classOfT, Map<String, Object> objMap, String... ids) {
        String tableName = getTableName(classOfT);
        SqlModel sqlModel = new SqlModel();
//        String setSql = "";
        StringBuilder setSqlSb = new StringBuilder("");
        for (Entry<String, Object> e : objMap.entrySet()) {
            Object value = e.getValue();
//            setSql += "," + e.getKey() + "=?";
            setSqlSb.append(",").append(e.getKey()).append("=?");
            sqlModel.addParam(value);
        }
        if (ids.length > 0) {
//            setSql += " where ";
            setSqlSb.append(" where ");
            for (int i = 0; i < ids.length; i++) {
                if (i != 0) {
//                    setSql += " and ";
                    setSqlSb.append(" and ");
                }
//                setSql += ids[i] + "=?";
                setSqlSb.append(ids[i]).append("=?");
                sqlModel.addParam(objMap.get(ids[i]));
            }
        } else {
//            setSql += " where id=?";
            setSqlSb.append(" where id=?");
            sqlModel.addParam(objMap.get("id"));
        }
        sqlModel.setSql("update " + tableName + " set " + setSqlSb.toString().substring(1));
        return sqlModel;
    }

    private <T> SqlModel getPkSqlModel(Class<T> classOfT, Map<String, Object> objMap, Map<String, Field> fieldMap, String... ids) {
        String tableName = getTableName(classOfT);
        SqlModel sqlModel = new SqlModel();
//        String setSql = "";
        StringBuilder setSqlSb = new StringBuilder("");
        if (ids.length > 0) {
//            setSql += " WHERE ";
            setSqlSb.append(" WHERE ");
            for (int i = 0; i < ids.length; i++) {
                if (i != 0) {
//                    setSql += " and ";
                    setSqlSb.append(" and ");
                }
//                setSql += ids[i] + "=?";
                setSqlSb.append(ids[i]).append("=?");
                sqlModel.addParam(objMap.get(ids[i]));
            }
        } else {
//            setSql += " WHERE id=?";
            setSqlSb.append(" WHERE id=?");
            sqlModel.addParam(objMap.get("id"));
        }
        sqlModel.setSql("SELECT " + StringUtils.join(fieldMap.keySet(), ",") + " FROM " + tableName + setSqlSb.toString());
        return sqlModel;
    }

    /**
     * 
     * 返回MAPLIST
     * 
     * @Title getMapList
     * @param queryModel
     *            查询条件
     * @return List<Map<String,Object>>
     */
    public <T> List<Map<String, Object>> getMapList(Class<T> classOfT, QueryModel queryModel) {
        String tableName = getTableName(classOfT);
        String sql = "SELECT " + queryModel.getSelectFields() + " FROM " + tableName + " " + queryModel.getOrderQueryStr();
        return getMapList(sql, queryModel.getParams());
    }

    /**
     * 
     * 返回LongList
     * 
     * @Title getLongList
     * @param queryModel
     *            查询条件
     * @return List<Long>
     */
    public <T> List<Long> getLongList(Class<T> classOfT, QueryModel queryModel) {
        String tableName = getTableName(classOfT);
        String sql = "select " + queryModel.getSelectFields() + " from " + tableName + " " + queryModel.getNoOrderQueryStr();
        return getLongList(sql, queryModel.getParams());
    }

    /**
     * 
     * 根据查询条件返回LIST结果集
     * 
     * @Title getList
     * @param queryModel
     * @return List<T>
     */
    public <T> List<T> getList(Class<T> classOfT, QueryModel queryModel) {
        String tableName = getTableName(classOfT);
        String sql = "select " + queryModel.getSelectFields() + " from " + tableName + " " + queryModel.getOrderQueryStr();
        return getList(classOfT, sql, queryModel.getParams());
    }

    /**
     * 
     * 返回当前表的最大ID
     * 
     * @Title getMaxId
     * @return long
     */
    public final <T> long getMaxId(Class<T> classOfT) {
        String tableName = getTableName(classOfT);
        String sql = " select Max(id) from " + tableName;
        return getLong(sql);
    }

    /**
     * 
     * 返回查询总数
     * 
     * @Title getCount
     * @return long
     */
    public final <T> long getCount(Class<T> classOfT) {
        String tableName = getTableName(classOfT);
        String sql = " select count(*) from " + tableName;
        return getLong(sql);
    }

    /**
     * 
     * 根据查询条件返回总数
     * 
     * @Title getCountBySql
     * @param sqlStr
     *            SQL条件
     * @return long
     */
    public final <T> long getCountBySql(Class<T> classOfT, String sqlStr) {
        String tableName = getTableName(classOfT);
        String sql = " select count(*) from " + tableName + " where " + sqlStr + "";
        return getLong(sql);
    }

    /**
     * 
     * 根据queryModel返回查询总数
     * 
     * @Title getCount
     * @param queryModel
     * @return long
     */
    public final <T> long getCount(Class<T> classOfT, QueryModel queryModel) {
        String tableName = getTableName(classOfT);
        String sql = " select count(*) from " + tableName + " " + queryModel.getNoOrderQueryStr();
        return getLong(sql, queryModel.getParams());
    }

    public boolean execSql(String sql, Object... params) throws Exception {
        int num = update(sql, params);
        log.debug(num + "");
        if (getException() != null) {
            throw getException();
        }
        return true;
    }

    /**
     * 获取可用id
     * 
     * @Title getIdLong
     * @author 吕凯
     * @date 2017年11月21日 上午11:12:43
     * @param classOfT
     * @return long
     */
    protected abstract <T> long getNextIdLong(Class<T> classOfT);

    /**
     * 获取序列的下一个可用值
     * 
     * @Title getNextValue
     * @author 吕凯
     * @date 2018年1月5日 上午9:43:45
     * @param classOfT
     * @return long
     */
    protected abstract <T> long getNextSeqValue(Class<T> classOfT, String fieldName);

    /**
     * 
     * 获取数据库事物异常
     * 
     * @Title getException
     * @return
     * @throws SQLException
     *             Exception
     */
    public Exception getException() {
        Exception exception = exceptionThreadLocal.get();
        if (exception != null) {
            return exception;
        }
        return null;
    }

    /**
     * 设置异常
     * 
     * @Title setException
     * @author 吕凯
     * @date 2019年3月29日 下午5:10:15
     * @param e
     * @throws SQLException
     *             void
     */
    public void setException(Exception e) {
        exceptionThreadLocal.set(e);
    }

    /**
     * 
     * 是否存在异常
     * 
     * @Title hasException
     * @return
     * @throws SQLException
     *             boolean
     */
    public boolean hasException() {
        return getException() != null;
    }
    // ====================================================================元方法===============================================================

}
